"""
任务管理服务层
将任务相关的业务逻辑从API层迁移到服务层
"""
from datetime import datetime
import logging
from typing import List, Optional, Dict, Any, Tuple
from bson import ObjectId, errors  # pyright: ignore[reportMissingImports]
from motor.motor_asyncio import AsyncIOMotorDatabase  # pyright: ignore[reportMissingImports]
from fastapi import HTTPException  # pyright: ignore[reportMissingImports]
from pymongo import ASCENDING, DESCENDING  # pyright: ignore[reportMissingImports]
try:
    from fastapi import status as http_status_module  # 避免与参数名 status 冲突
except ImportError:
    from starlette import status as http_status_module  # 后备导入

from app.schemas.task import (
    TaskCreate,
    TaskUpdate,
    TaskStatusUpdate,
    TaskAssigneeUpdate
)
from app.models.task import (
    TaskTimeLog
)
from app.core.permissions import Permissions
from app.core.state_validator import get_state_validator
from app.utils.task_utils import format_task_response
from app.services.notification_service import NotificationService
from app.models.notification import NotificationCreate, NotificationType, RelatedObjectType
import asyncio

logger = logging.getLogger(__name__)


class TaskService:
    """任务服务类，封装任务相关的业务逻辑"""
    
    def __init__(self, db: AsyncIOMotorDatabase):
        self.db = db
        self._state_validator = None  # 缓存状态验证器实例
    
    @staticmethod
    def _get_status_code(status_name: str, default: int = 500) -> int:
        """安全地获取HTTP状态码"""
        try:
            if http_status_module is None:
                return default
            return getattr(http_status_module, status_name, default)
        except (AttributeError, TypeError):
            return default
    
    def _to_object_id(self, value: Any, field_name: str = "ID") -> Optional[ObjectId]:
        """将值转换为ObjectId，如果无效则返回None"""
        if value is None:
            return None
        if isinstance(value, ObjectId):
            return value
        if isinstance(value, str) and ObjectId.is_valid(value):
            return ObjectId(value)
        return None
    
    def _validate_object_id(self, value: Any, field_name: str = "ID") -> ObjectId:
        """验证并转换ObjectId，如果无效则抛出异常"""
        obj_id = self._to_object_id(value, field_name)
        if obj_id is None:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                detail=f"无效的{field_name}格式"
            )
        return obj_id
    
    async def _check_task_permission(
        self,
        task: Dict[str, Any],
        current_user: dict,
        permission: str,
        project_permission: Optional[str] = None
    ) -> bool:
        """
        检查用户是否有权限操作任务
        
        权限检查顺序：
        1. 检查是否为管理员（拥有所有权限）
        2. 检查是否为任务创建者
        3. 检查项目成员权限（优先，如果任务有项目ID）
        4. 如果任务没有项目ID，检查全局权限（向后兼容）
        
        注意：项目权限应该优先于全局权限，只有项目成员才能操作项目资源。
        """
        from app.services.permission_service import PermissionService
        
        user_permissions = current_user.get("permissions", [])
        user_id = current_user.get("user_id")
        
        # 检查是否为管理员（拥有所有权限）
        if Permissions.ADMIN in user_permissions or "*" in user_permissions:
            return True
        
        # 检查是否为任务创建者
        task_created_by = task.get("created_by")
        if task_created_by:
            if isinstance(task_created_by, ObjectId):
                if str(task_created_by) == user_id:
                    return True
            elif task_created_by == user_id:
                return True
        
        # 优先检查项目成员权限（如果任务有项目ID）
        project_id = task.get("project_id")
        if project_id:
            project_id_str = str(project_id) if isinstance(project_id, ObjectId) else project_id
            # 使用项目成员权限检查（不再回退到全局权限）
            required_perm = project_permission or permission
            return await PermissionService.check_project_member_permission(
                project_id_str, current_user, self.db, required_perm
            )
        
        # 如果任务没有项目ID，检查全局权限（向后兼容，用于系统级任务）
        return PermissionService.has_permission(current_user, permission)
    
    async def _get_task_with_relations(self, task_id: ObjectId) -> Tuple[Dict[str, Any], Dict[str, Any]]:
        """获取任务及其关联信息"""
        task = await self.db.tasks.find_one({"_id": task_id})
        if not task:
            return None, {}
        
        # 收集需要查询的ID
        user_ids = set()
        project_ids = set()
        
        if task.get("assignee_id"):
            user_ids.add(task["assignee_id"])
        if task.get("reporter_id"):
            user_ids.add(task["reporter_id"])
        if task.get("created_by"):
            user_ids.add(task["created_by"])
        if task.get("project_id"):
            project_ids.add(task["project_id"])
        
        # 批量查询关联信息
        relations = {}
        
        if user_ids:
            users = await self.db.users.find(
                {"_id": {"$in": list(user_ids)}},
                {"_id": 1, "name": 1, "avatar": 1, "username": 1}
            ).to_list(length=None)
            relations["users"] = {str(user["_id"]): user for user in users}
        
        if project_ids:
            projects = await self.db.projects.find(
                {"_id": {"$in": list(project_ids)}},
                {"_id": 1, "name": 1}
            ).to_list(length=None)
            relations["projects"] = {str(project["_id"]): project for project in projects}
        
        # 查询版本关联
        task_relation = await self.db.version_task_relations.find_one(
            {"task_id": task_id}
        )
        if task_relation:
            version = await self.db.versions.find_one(
                {"_id": task_relation["version_id"]},
                {"_id": 1, "name": 1, "version_number": 1}
            )
            if version:
                relations["version"] = version
        
        return task, relations
    
    async def list_tasks(
        self,
        current_user: dict,
        *,
        page: Optional[int] = None,
        skip: Optional[int] = None,
        limit: Optional[int] = None,
        size: Optional[int] = None,
        search: Optional[str] = None,
        project_id: Optional[str] = None,
        assignee_id: Optional[str] = None,
        reporter_id: Optional[str] = None,
        status: Optional[str] = None,
        priority: Optional[str] = None,
        task_type: Optional[str] = None,
        due_date_start: Optional[str] = None,
        due_date_end: Optional[str] = None,
        due_date_from: Optional[str] = None,
        due_date_to: Optional[str] = None,
        tags: Optional[str] = None,
        version: Optional[str] = None,
        version_id: Optional[str] = None,
        requirement_id: Optional[str] = None,
        sort_by: str = "created_at",
        sort_order: Optional[str] = "desc"
    ) -> Dict[str, Any]:
        """
        获取任务列表（分页）
        """
        # 处理分页参数：优先使用size（兼容前端），然后使用limit
        page_size = size if size is not None else (limit if limit is not None else 20)
        
        # 处理分页参数：优先使用page，如果提供了skip则使用skip
        if page is not None:
            skip_value = (page - 1) * page_size
        elif skip is not None:
            skip_value = skip
        else:
            skip_value = 0
        
        # 处理日期参数：兼容前端参数名
        if due_date_from and not due_date_start:
            due_date_start = due_date_from
        if due_date_to and not due_date_end:
            due_date_end = due_date_to
        
        # 参数验证和处理空字符串
        if status == "":
            status = None
        if priority == "":
            priority = None
        if task_type == "":
            task_type = None
        if sort_order == "":
            sort_order = "desc"
        
        # 处理空字符串参数
        if search == "":
            search = None
        if project_id == "":
            project_id = None
        if assignee_id == "":
            assignee_id = None
        if reporter_id == "":
            reporter_id = None
        if version_id == "":
            version_id = None
        if requirement_id == "":
            requirement_id = None
        if tags == "":
            tags = None
        if version == "":
            version = None
        if due_date_from == "":
            due_date_from = None
        if due_date_to == "":
            due_date_to = None
        if due_date_start == "":
            due_date_start = None
        if due_date_end == "":
            due_date_end = None
        
        # 验证枚举值 - 使用动态状态校验
        validator = get_state_validator(self.db)
        
        if status:
            is_valid = await validator.validate_state_code("task", status)
            if not is_valid:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                    detail=f"Invalid status value: {status}"
                )
        
        if priority:
            # 优先级应该从 priorities 集合中验证
            priority_doc = await self.db.priorities.find_one({
                "module_type": "task",
                "code": priority,
                "is_enabled": True
            })
            if not priority_doc:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                    detail=f"Invalid priority value: {priority}"
                )
        
        if sort_order and sort_order not in ["asc", "desc"]:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                detail=f"Invalid sort_order value: {sort_order}"
            )
        
        # 处理版本ID筛选 - 通过关联表查询
        version_task_ids = None
        if version_id:
            try:
                version_obj_id = ObjectId(version_id)
                task_relations = await self.db.version_task_relations.find(
                    {"version_id": version_obj_id}
                ).to_list(length=None)
                version_task_ids = [relation["task_id"] for relation in task_relations]
                if not version_task_ids:
                    return {
                        "items": [],
                        "total": 0,
                        "page": (skip_value // page_size) + 1 if page_size > 0 else 1,
                        "size": page_size
                    }
            except Exception:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                    detail="Invalid version_id format"
                )
        
        # 处理需求ID筛选
        requirement_task_ids = None
        if requirement_id:
            try:
                requirement_obj_id = ObjectId(requirement_id)
                # 方式1: 直接通过任务的 requirement_id 字段查询
                direct_tasks = await self.db.tasks.find(
                    {"requirement_id": requirement_obj_id},
                    {"_id": 1}
                ).to_list(length=None)
                direct_task_ids = [task["_id"] for task in direct_tasks]
                
                # 方式2: 通过版本任务关联表查询
                task_relations = await self.db.version_task_relations.find(
                    {"requirement_id": requirement_obj_id}
                ).to_list(length=None)
                version_task_ids_from_req = [relation["task_id"] for relation in task_relations]
                
                # 合并两种方式的任务ID（去重）
                requirement_task_ids = list(set(direct_task_ids + version_task_ids_from_req))
                
                if not requirement_task_ids:
                    return {
                        "items": [],
                        "total": 0,
                        "page": (skip_value // page_size) + 1 if page_size > 0 else 1,
                        "size": page_size
                    }
            except Exception:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                    detail="Invalid requirement_id format"
                )
        
        # 构建基础查询条件
        base_query = {}
        
        # 如果通过version_id或requirement_id筛选，需要合并任务ID限制
        task_ids_filter = None
        if version_task_ids and requirement_task_ids:
            task_ids_filter = list(set(version_task_ids) & set(requirement_task_ids))
        elif version_task_ids:
            task_ids_filter = version_task_ids
        elif requirement_task_ids:
            task_ids_filter = requirement_task_ids
        
        if task_ids_filter:
            base_query["_id"] = {"$in": task_ids_filter}
        
        if search:
            base_query["$and"] = base_query.get("$and", [])
            base_query["$and"].append({
                "$or": [
                    {"title": {"$regex": search, "$options": "i"}},
                    {"description": {"$regex": search, "$options": "i"}},
                    {"tags": {"$in": [{"$regex": search, "$options": "i"}]}}
                ]
            })
        
        if project_id:
            try:
                base_query["project_id"] = ObjectId(project_id)
            except Exception:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                    detail="Invalid project_id format"
                )
        
        if assignee_id:
            try:
                base_query["assignee_id"] = ObjectId(assignee_id)
            except Exception:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                    detail="Invalid assignee_id format"
                )
        
        if reporter_id:
            try:
                base_query["reporter_id"] = ObjectId(reporter_id)
            except Exception:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                    detail="Invalid reporter_id format"
                )
        
        if status:
            base_query["status"] = status
        
        if priority:
            base_query["priority"] = priority
        
        if task_type:
            base_query["type"] = task_type
        
        # 日期范围筛选
        date_start = due_date_start or due_date_from
        date_end = due_date_end or due_date_to
        
        if date_start or date_end:
            date_query = {}
            if date_start:
                try:
                    if len(date_start) == 10:  # YYYY-MM-DD
                        date_start = date_start + " 00:00:00"
                    date_query["$gte"] = datetime.fromisoformat(date_start.replace('Z', '+00:00'))
                except (ValueError, AttributeError):
                    raise HTTPException(
                        status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                        detail=f"Invalid due_date_start format: {date_start}"
                    )
            if date_end:
                try:
                    if len(date_end) == 10:  # YYYY-MM-DD
                        date_end = date_end + " 23:59:59"
                    date_query["$lte"] = datetime.fromisoformat(date_end.replace('Z', '+00:00'))
                except (ValueError, AttributeError):
                    raise HTTPException(
                        status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                        detail=f"Invalid due_date_end format: {date_end}"
                    )
            base_query["due_date"] = date_query
        
        if tags:
            tag_list = [tag.strip() for tag in tags.split(",")]
            base_query["tags"] = {"$in": tag_list}
        
        # 版本筛选
        if version and not version_id:
            if "$or" not in base_query:
                base_query["$or"] = []
            elif not isinstance(base_query["$or"], list):
                base_query["$or"] = [base_query["$or"]]
            base_query["$or"].append({"version": version})
        
        # 使用统一的数据权限过滤方法
        from app.services.permission_service import PermissionService
        query = await PermissionService.build_data_permission_query(
            user=current_user,
            db=self.db,
            module_type="task",
            base_query=base_query,
            project_id_field="project_id",
            assignee_id_field="assignee_id",
            reporter_id_field="reporter_id",
            creator_id_field="created_by",
            read_all_permission=Permissions.TASK_READ_ALL
        )
        
        # 排序
        if not sort_by or sort_by.strip() == "":
            sort_by = "created_at"
        sort_direction = ASCENDING if sort_order == "asc" else DESCENDING
        sort_criteria = [(sort_by, sort_direction)]
        
        # 获取总数用于分页
        total = await self.db.tasks.count_documents(query)
        
        # 查询任务
        cursor = self.db.tasks.find(query).sort(sort_criteria).skip(skip_value).limit(page_size)
        tasks = await cursor.to_list(length=page_size)
        
        # 收集需要查询的用户ID和项目ID
        user_ids = set()
        project_ids = set()
        task_ids = []
        
        for task in tasks:
            task_ids.append(task["_id"])
            if task.get("assignee_id"):
                user_ids.add(task["assignee_id"])
            if task.get("reporter_id"):
                user_ids.add(task["reporter_id"])
            if task.get("created_by"):
                user_ids.add(task["created_by"])
            if task.get("project_id"):
                project_ids.add(task["project_id"])
        
        # 批量查询用户信息
        users_dict = {}
        if user_ids:
            users = await self.db.users.find(
                {"_id": {"$in": list(user_ids)}},
                {"_id": 1, "name": 1, "avatar": 1}
            ).to_list(length=None)
            users_dict = {str(user["_id"]): user for user in users}
        
        # 批量查询项目信息
        projects_dict = {}
        if project_ids:
            projects = await self.db.projects.find(
                {"_id": {"$in": list(project_ids)}},
                {"_id": 1, "name": 1}
            ).to_list(length=None)
            projects_dict = {str(project["_id"]): project for project in projects}
        
        # 批量查询任务关联的版本信息
        versions_dict = {}
        task_versions_map = {}
        if task_ids:
            task_relations = await self.db.version_task_relations.find(
                {"task_id": {"$in": task_ids}}
            ).to_list(length=None)
            
            version_ids = set()
            for relation in task_relations:
                version_ids.add(relation["version_id"])
            
            if version_ids:
                versions = await self.db.versions.find(
                    {"_id": {"$in": list(version_ids)}},
                    {"_id": 1, "name": 1, "version_number": 1}
                ).to_list(length=None)
                versions_dict = {str(v["_id"]): v for v in versions}
            
            for relation in task_relations:
                task_id_str = str(relation["task_id"])
                version_id_str = str(relation["version_id"])
                if task_id_str not in task_versions_map:
                    task_versions_map[task_id_str] = []
                if version_id_str in versions_dict:
                    task_versions_map[task_id_str].append(versions_dict[version_id_str])
        
        # 转换为响应模型
        result = []
        for task in tasks:
            assignee_info = users_dict.get(str(task["assignee_id"])) if task.get("assignee_id") else None
            reporter_info = users_dict.get(str(task["reporter_id"])) if task.get("reporter_id") else None
            creator_info = users_dict.get(str(task["created_by"])) if task.get("created_by") else None
            project_info = projects_dict.get(str(task["project_id"])) if task.get("project_id") else None
            
            task_versions = task_versions_map.get(str(task["_id"]), [])
            version_info = task_versions[0] if task_versions else None
            
            task_response = format_task_response(
                task=task,
                assignee_info=assignee_info,
                reporter_info=reporter_info,
                creator_info=creator_info,
                project_info=project_info,
                version_info=version_info,
                include_details=False
            )
            result.append(task_response)
        
        # 计算分页信息
        current_page = page if page is not None else (skip_value // page_size) + 1
        
        return {
            "items": result,
            "total": total,
            "page": current_page,
            "size": page_size
        }
    
    async def get_task(
        self,
        task_id: str,
        current_user: dict
    ) -> Dict[str, Any]:
        """
        获取任务详情
        """
        object_id = self._validate_object_id(task_id, "任务ID")
        
        task, relations = await self._get_task_with_relations(object_id)
        if not task:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_404_NOT_FOUND', 404),
                detail="Task not found"
            )
        
        # 权限检查
        user_permissions = current_user.get("permissions", [])
        user_id = ObjectId(current_user.get("user_id"))
        
        has_access = (
            Permissions.TASK_READ_ALL in user_permissions or
            Permissions.ADMIN in user_permissions or
            task.get("assignee_id") == user_id or
            task.get("reporter_id") == user_id or
            task.get("created_by") == user_id
        )
        
        if not has_access and task.get("project_id"):
            project = await self.db.projects.find_one({"_id": task["project_id"]})
            if project:
                has_access = (
                    project["is_public"] or
                    project["created_by"] == user_id or
                    any(member["user_id"] == user_id for member in project.get("members", []))
                )
        
        if not has_access:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_403_FORBIDDEN', 403),
                detail="Not enough permissions to access this task"
            )
        
        # 获取关联信息
        users_dict = relations.get("users", {})
        projects_dict = relations.get("projects", {})
        version_info = relations.get("version")
        
        assignee_info = users_dict.get(str(task["assignee_id"])) if task.get("assignee_id") else None
        reporter_info = users_dict.get(str(task["reporter_id"])) if task.get("reporter_id") else None
        creator_info = users_dict.get(str(task["created_by"])) if task.get("created_by") else None
        project_info = projects_dict.get(str(task["project_id"])) if task.get("project_id") else None
        
        task_data = format_task_response(
            task=task,
            assignee_info=assignee_info,
            reporter_info=reporter_info,
            creator_info=creator_info,
            project_info=project_info,
            version_info=version_info,
            include_details=True
        )
        
        return task_data
    
    async def create_task(
        self,
        task_in: TaskCreate,
        current_user: dict
    ) -> Dict[str, Any]:
        """
        创建任务
        """
        # 检查权限
        user_permissions = current_user.get("permissions", [])
        if Permissions.TASK_CREATE not in user_permissions and Permissions.ADMIN not in user_permissions:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_403_FORBIDDEN', 403),
                detail="Not enough permissions to create task"
            )
        
        # 验证项目是否存在且有权限
        if task_in.project_id:
            project_object_id = self._validate_object_id(task_in.project_id, "项目ID")
            project = await self.db.projects.find_one({"_id": project_object_id})
            if not project:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_404_NOT_FOUND', 404),
                    detail="Project not found"
                )
            
            user_id = ObjectId(current_user.get("user_id"))
            has_project_access = (
                Permissions.PROJECT_READ_ALL in user_permissions or
                Permissions.ADMIN in user_permissions or
                project["is_public"] or
                project["created_by"] == user_id or
                any(member["user_id"] == user_id for member in project.get("members", []))
            )
            
            if not has_project_access:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_403_FORBIDDEN', 403),
                    detail="Not enough permissions to create task in this project"
                )
        
        # 验证负责人是否存在
        if task_in.assignee_id:
            assignee_object_id = self._validate_object_id(task_in.assignee_id, "负责人ID")
            assignee = await self.db.users.find_one({"_id": assignee_object_id})
            if not assignee:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_404_NOT_FOUND', 404),
                    detail="Assignee not found"
                )
        
        # 创建任务文档
        task_doc = task_in.model_dump()
        # 修复字段名，将task_type映射到数据库的type字段
        if "task_type" in task_doc:
            task_doc["type"] = task_doc.pop("task_type")
        task_doc.update({
            "created_by": ObjectId(current_user.get("user_id")),
            "created_at": datetime.utcnow(),
            "updated_at": datetime.utcnow(),
            "comments": [],
            "attachments": [],
            "time_logs": []
        })
        
        # 转换ObjectId字段
        if task_doc.get("project_id"):
            task_doc["project_id"] = ObjectId(task_doc["project_id"])
        if task_doc.get("assignee_id"):
            task_doc["assignee_id"] = ObjectId(task_doc["assignee_id"])
        if task_doc.get("reporter_id"):
            task_doc["reporter_id"] = ObjectId(task_doc["reporter_id"])
        if task_doc.get("requirement_id"):
            task_doc["requirement_id"] = ObjectId(task_doc["requirement_id"])
        if task_doc.get("dependencies"):
            task_doc["dependencies"] = [ObjectId(dep) for dep in task_doc["dependencies"]]
        
        # 插入数据库
        result = await self.db.tasks.insert_one(task_doc)
        
        # 获取创建的任务
        created_task = await self.db.tasks.find_one({"_id": result.inserted_id})
        if not created_task:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_500_INTERNAL_SERVER_ERROR', 500),
                detail="Failed to create task"
            )
        
        # 转换为响应模型
        task_data = {
            "id": str(created_task["_id"]),
            "title": created_task["title"],
            "description": created_task.get("description"),
            "task_type": created_task["type"],
            "status": created_task["status"],
            "priority": created_task["priority"],
            "project_id": str(created_task["project_id"]) if created_task.get("project_id") else None,
            "assignee_id": str(created_task["assignee_id"]) if created_task.get("assignee_id") else None,
            "reporter_id": str(created_task["reporter_id"]) if created_task.get("reporter_id") else None,
            "estimated_hours": created_task.get("estimated_hours"),
            "actual_hours": created_task.get("actual_hours"),
            "start_date": created_task.get("start_date"),
            "due_date": created_task.get("due_date"),
            "tags": created_task.get("tags", []),
            "dependencies": [str(dep) for dep in created_task.get("dependencies", [])],
            "organization_id": str(created_task["organization_id"]) if created_task.get("organization_id") else None,
            "comments": [],
            "attachments": [],
            "time_logs": [],
            "created_by": str(created_task["created_by"]),
            "created_at": created_task["created_at"],
            "updated_at": created_task["updated_at"],
            "comment_count": 0,
            "attachment_count": 0,
            "total_time_spent": 0.0
        }
        
        # 触发通知：如果任务有负责人，通知负责人
        if created_task.get("assignee_id") and str(created_task["assignee_id"]) != current_user.get("user_id"):
            try:
                creator = await self.db.users.find_one({"_id": ObjectId(current_user.get("user_id"))})
                creator_name = creator.get("name") or creator.get("username", "系统") if creator else "系统"
                
                notification_data = NotificationCreate(
                    user_id=str(created_task["assignee_id"]),
                    type=NotificationType.TASK_ASSIGNED,
                    title=f"新任务分配：{created_task['title']}",
                    content=f"{creator_name} 将任务「{created_task['title']}」分配给了您",
                    related_type=RelatedObjectType.TASK,
                    related_id=str(created_task["_id"])
                )
                asyncio.create_task(
                    NotificationService.create_notification(db=self.db, notification_data=notification_data, send_email=True)
                )
            except Exception as e:
                logger.warning(f"发送任务分配通知失败: {str(e)}")
        
        return task_data
    
    async def update_task(
        self,
        task_id: str,
        task_in: TaskUpdate,
        current_user: dict
    ) -> Dict[str, Any]:
        """
        更新任务信息
        """
        object_id = self._validate_object_id(task_id, "任务ID")
        
        # 检查任务是否存在
        task = await self.db.tasks.find_one({"_id": object_id})
        if not task:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_404_NOT_FOUND', 404),
                detail="Task not found"
            )
        
        # 权限检查
        has_permission = await self._check_task_permission(
            task, current_user, Permissions.TASK_UPDATE, "task:update"
        )
        
        if not has_permission:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_403_FORBIDDEN', 403),
                detail="Not enough permissions to update this task"
            )
        
        # 构建更新数据
        update_data = task_in.model_dump(exclude_unset=True)
        
        # 转换ObjectId字段
        if "project_id" in update_data and update_data["project_id"]:
            update_data["project_id"] = self._validate_object_id(update_data["project_id"], "项目ID")
        
        if "assignee_id" in update_data and update_data["assignee_id"]:
            update_data["assignee_id"] = self._validate_object_id(update_data["assignee_id"], "负责人ID")
        
        if "reporter_id" in update_data and update_data["reporter_id"]:
            update_data["reporter_id"] = self._validate_object_id(update_data["reporter_id"], "报告人ID")
        
        if "dependencies" in update_data and update_data["dependencies"]:
            try:
                update_data["dependencies"] = [ObjectId(dep) for dep in update_data["dependencies"]]
            except Exception:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                    detail="Invalid dependencies format"
                )
        
        # 处理空字符串和None值
        fields_to_unset = []
        for key, value in list(update_data.items()):
            if value == "" or value is None:
                if key in ["assignee_id", "reporter_id", "parent_task_id", "description"]:
                    if value == "":
                        update_data[key] = None
                elif key in ["start_date", "due_date"]:
                    if value == "":
                        update_data[key] = None
                elif key in ["tags"]:
                    if value == []:
                        update_data[key] = []
                elif key in ["progress", "estimated_hours", "actual_hours"]:
                    if value == "" or value is None:
                        update_data[key] = 0
                    elif isinstance(value, (int, float)):
                        if key == "progress":
                            update_data[key] = max(0, min(100, int(value)))
                        else:
                            update_data[key] = max(0, float(value))
                else:
                    if value == "":
                        fields_to_unset.append(key)
                        del update_data[key]
        
        # 检查状态是否更新为已完成，如果是则自动设置进度为100
        if "status" in update_data:
            new_status = update_data["status"]
            validator = get_state_validator(self.db)
            try:
                state_info = await validator.get_state_info("task", new_status)
                if state_info:
                    state_name = ""
                    state_description = ""
                    if hasattr(state_info, "name"):
                        state_name = getattr(state_info, "name", "")
                        state_description = getattr(state_info, "description", "") or ""
                    elif isinstance(state_info, dict):
                        state_name = state_info.get("name", "")
                        state_description = state_info.get("description", "") or ""
                    
                    completed_keywords = ["已完成", "完成", "完成状态"]
                    is_completed = any(keyword in state_name or keyword in state_description 
                                     for keyword in completed_keywords)
                    
                    if is_completed:
                        update_data["progress"] = 100
            except Exception:
                pass
        
        # 更新任务
        if update_data:
            update_data["updated_at"] = datetime.utcnow()
            update_op = {"$set": update_data}
            
            if fields_to_unset:
                update_op["$unset"] = {field: "" for field in fields_to_unset}
            
            await self.db.tasks.update_one(
                {"_id": object_id},
                update_op
            )
        
        # 获取更新后的任务
        updated_task, relations = await self._get_task_with_relations(object_id)
        
        # 获取关联信息
        users_dict = relations.get("users", {})
        projects_dict = relations.get("projects", {})
        version_info = relations.get("version")
        
        assignee_info = users_dict.get(str(updated_task["assignee_id"])) if updated_task.get("assignee_id") else None
        reporter_info = users_dict.get(str(updated_task["reporter_id"])) if updated_task.get("reporter_id") else None
        creator_info = users_dict.get(str(updated_task["created_by"])) if updated_task.get("created_by") else None
        project_info = projects_dict.get(str(updated_task["project_id"])) if updated_task.get("project_id") else None
        
        task_data = format_task_response(
            task=updated_task,
            assignee_info=assignee_info,
            reporter_info=reporter_info,
            creator_info=creator_info,
            project_info=project_info,
            version_info=version_info,
            include_details=True
        )
        
        # 触发通知：任务更新时通知负责人
        if updated_task.get("assignee_id") and str(updated_task["assignee_id"]) != current_user.get("user_id"):
            try:
                creator = await self.db.users.find_one({"_id": ObjectId(current_user.get("user_id"))})
                creator_name = creator.get("name") or creator.get("username", "系统") if creator else "系统"
                task_title = updated_task.get("title", "任务")
                
                notification_data = NotificationCreate(
                    user_id=str(updated_task["assignee_id"]),
                    type=NotificationType.TASK_UPDATED,
                    title=f"任务更新：{task_title}",
                    content=f"{creator_name} 更新了任务「{task_title}」",
                    related_type=RelatedObjectType.TASK,
                    related_id=task_id
                )
                asyncio.create_task(
                    NotificationService.create_notification(db=self.db, notification_data=notification_data, send_email=False)
                )
            except Exception as e:
                logger.warning(f"发送任务更新通知失败: {str(e)}")
        
        return task_data
    
    async def delete_task(
        self,
        task_id: str,
        current_user: dict
    ) -> None:
        """
        删除任务
        """
        object_id = self._validate_object_id(task_id, "任务ID")
        
        # 检查任务是否存在
        task = await self.db.tasks.find_one({"_id": object_id})
        if not task:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_404_NOT_FOUND', 404),
                detail="Task not found"
            )
        
        # 权限检查
        has_permission = await self._check_task_permission(
            task, current_user, Permissions.TASK_DELETE, "task:delete"
        )
        
        if not has_permission:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_403_FORBIDDEN', 403),
                detail="Not enough permissions to delete this task"
            )
        
        # 触发通知：任务删除时通知负责人
        if task.get("assignee_id") and str(task["assignee_id"]) != current_user.get("user_id"):
            try:
                creator = await self.db.users.find_one({"_id": ObjectId(current_user.get("user_id"))})
                creator_name = creator.get("name") or creator.get("username", "系统") if creator else "系统"
                task_title = task.get("title", "任务")
                
                notification_data = NotificationCreate(
                    user_id=str(task["assignee_id"]),
                    type=NotificationType.TASK_DELETED,
                    title=f"任务已删除：{task_title}",
                    content=f"{creator_name} 删除了任务「{task_title}」",
                    related_type=RelatedObjectType.TASK,
                    related_id=task_id
                )
                asyncio.create_task(
                    NotificationService.create_notification(db=self.db, notification_data=notification_data, send_email=False)
                )
            except Exception as e:
                logger.warning(f"发送任务删除通知失败: {str(e)}")
        
        # 删除任务
        await self.db.tasks.delete_one({"_id": object_id})
    
    async def update_task_status(
        self,
        task_id: str,
        status_update: TaskStatusUpdate,
        current_user: dict
    ) -> Dict[str, Any]:
        """
        更新任务状态
        """
        object_id = self._validate_object_id(task_id, "任务ID")
        
        # 检查任务是否存在
        task = await self.db.tasks.find_one({"_id": object_id})
        if not task:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_404_NOT_FOUND', 404),
                detail="Task not found"
            )
        
        # 权限检查
        user_permissions = current_user.get("permissions", [])
        user_id = ObjectId(current_user.get("user_id"))
        
        has_permission = (
            Permissions.TASK_UPDATE in user_permissions or
            Permissions.ADMIN in user_permissions or
            task.get("assignee_id") == user_id or
            task.get("reporter_id") == user_id or
            task.get("created_by") == user_id
        )
        
        if not has_permission:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_403_FORBIDDEN', 403),
                detail="Not enough permissions to update task status"
            )
        
        # 验证状态代码是否有效
        validator = get_state_validator(self.db)
        
        # 直接从数据库查询状态数据
        states_cursor = self.db.states.find({
            "module_type": "task",
            "is_enabled": True
        }).sort("sort_order", 1)
        states_list = await states_cursor.to_list(length=None)
        
        valid_status_codes = [state.get("code") for state in states_list if state.get("code")]
        is_valid = status_update.status in valid_status_codes
        
        if not is_valid:
            logger.warning(f"状态验证失败: {status_update.status}, 数据库中的有效状态代码: {valid_status_codes}")
            
            # 兼容性处理：如果前端发送的是 review，但数据库中是 in_review，进行映射
            if status_update.status == "review":
                in_review_state = next((state for state in states_list if state.get("code") == "in_review"), None)
                
                if not in_review_state:
                    existing_in_review = await self.db.states.find_one({
                        "module_type": "task",
                        "code": "in_review"
                    })
                    
                    now = datetime.utcnow()
                    if existing_in_review:
                        await self.db.states.update_one(
                            {"_id": existing_in_review["_id"]},
                            {
                                "$set": {
                                    "name": existing_in_review.get("name") or "审查中",
                                    "color": existing_in_review.get("color") or "#722ed1",
                                    "sort_order": existing_in_review.get("sort_order", 4),
                                    "description": existing_in_review.get("description") or "任务处于审查阶段",
                                    "is_enabled": True,
                                    "is_visible": True,
                                    "updated_at": now
                                }
                            }
                        )
                        in_review_state = await self.db.states.find_one({"_id": existing_in_review["_id"]})
                    else:
                        new_state = {
                            "name": "审查中",
                            "code": "in_review",
                            "module_type": "task",
                            "color": "#722ed1",
                            "sort_order": 4,
                            "description": "任务处于审查阶段",
                            "is_enabled": True,
                            "is_visible": True,
                            "is_default": False,
                            "created_at": now,
                            "updated_at": now
                        }
                        insert_result = await self.db.states.insert_one(new_state)
                        in_review_state = await self.db.states.find_one({"_id": insert_result.inserted_id})
                    
                    from app.core.state_cache import state_cache
                    state_cache.invalidate_cache("task")
                    
                    if in_review_state:
                        states_list.append(in_review_state)
                        valid_status_codes.append("in_review")
                
                if in_review_state:
                    status_update.status = "in_review"
                    is_valid = True
                    logger.info("状态映射: review -> in_review（自动补充 in_review 状态）")
            
            if not is_valid:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_400_BAD_REQUEST', 400),
                    detail=f"Invalid status value: {status_update.status}. Valid statuses: {', '.join(valid_status_codes)}"
                )
        
        # 检查状态是否为已完成状态，如果是则自动设置进度为100
        update_fields = {
            "status": status_update.status,
            "updated_at": datetime.utcnow()
        }
        
        try:
            current_state = None
            for state in states_list:
                if state.get("code") == status_update.status:
                    current_state = state
                    break
            
            if current_state:
                state_name = current_state.get("name", "")
                state_description = current_state.get("description", "") or ""
                
                completed_keywords = ["已完成", "完成", "完成状态"]
                is_completed = any(keyword in state_name or keyword in state_description 
                                 for keyword in completed_keywords)
                
                if is_completed:
                    update_fields["progress"] = 100
                    logger.info(f"状态 {status_update.status} ({state_name}) 被识别为已完成状态，自动设置进度为100%")
                    
                    current_actual_hours = task.get("actual_hours")
                    time_logs = task.get("time_logs", [])
                    
                    if (current_actual_hours is None or current_actual_hours == 0) and not time_logs:
                        start_date = task.get("start_date")
                        if start_date:
                            current_time = datetime.utcnow()
                            if isinstance(start_date, datetime):
                                time_diff = current_time - start_date
                                calculated_hours = round(time_diff.total_seconds() / 3600, 2)
                                if calculated_hours > 0:
                                    update_fields["actual_hours"] = calculated_hours
                                    logger.info(f"任务 {task_id} 状态更新为已完成，根据开始时间计算实际工时为 {calculated_hours} 小时")
                        else:
                            created_at = task.get("created_at")
                            if created_at:
                                current_time = datetime.utcnow()
                                if isinstance(created_at, datetime):
                                    time_diff = current_time - created_at
                                    calculated_hours = round(time_diff.total_seconds() / 3600, 2)
                                    if calculated_hours > 0:
                                        update_fields["actual_hours"] = calculated_hours
                                        logger.info(f"任务 {task_id} 状态更新为已完成，根据创建时间计算实际工时为 {calculated_hours} 小时")
        except Exception as e:
            logger.warning(f"获取状态信息失败: {str(e)}")
        
        # 更新任务状态
        await self.db.tasks.update_one(
            {"_id": object_id},
            {"$set": update_fields}
        )
        
        # 获取更新后的任务信息
        updated_task, relations = await self._get_task_with_relations(object_id)
        
        # 获取关联信息
        users_dict = relations.get("users", {})
        projects_dict = relations.get("projects", {})
        version_info = relations.get("version")
        
        assignee_info = users_dict.get(str(updated_task["assignee_id"])) if updated_task.get("assignee_id") else None
        reporter_info = users_dict.get(str(updated_task["reporter_id"])) if updated_task.get("reporter_id") else None
        creator_info = users_dict.get(str(updated_task["created_by"])) if updated_task.get("created_by") else None
        project_info = projects_dict.get(str(updated_task["project_id"])) if updated_task.get("project_id") else None
        
        task_data = format_task_response(
            task=updated_task,
            assignee_info=assignee_info,
            reporter_info=reporter_info,
            creator_info=creator_info,
            project_info=project_info,
            version_info=version_info,
            include_details=False
        )
        
        # 触发版本状态流转检查（异步，不阻塞响应）
        try:
            from app.utils.version_transition_trigger import trigger_version_transition_check
            asyncio.create_task(trigger_version_transition_check(self.db, "task", object_id))
        except Exception as e:
            logger.warning(f"触发版本状态流转检查失败: {str(e)}")
        
        # 触发通知：任务状态变更时通知相关人员
        try:
            old_status = task.get("status")
            new_status = status_update.status
            
            if old_status != new_status:
                state_doc = await self.db.states.find_one({
                    "module_type": "task",
                    "code": new_status
                })
                status_name = state_doc.get("name", new_status) if state_doc else new_status
                
                current_user_obj = await self.db.users.find_one({"_id": user_id})
                current_user_name = current_user_obj.get("name") or current_user_obj.get("username", "系统") if current_user_obj else "系统"
                
                # 通知任务创建者
                if task.get("created_by") and task["created_by"] != user_id:
                    notification_data = NotificationCreate(
                        user_id=str(task["created_by"]),
                        type=NotificationType.TASK_STATUS_CHANGED,
                        title=f"任务状态更新：{task['title']}",
                        content=f"{current_user_name} 将任务「{task['title']}」的状态更新为「{status_name}」",
                        related_type=RelatedObjectType.TASK,
                        related_id=task_id
                    )
                    asyncio.create_task(
                        NotificationService.create_notification(db=self.db, notification_data=notification_data, send_email=False)
                    )
                
                # 通知任务负责人
                if task.get("assignee_id") and task["assignee_id"] != user_id and task["assignee_id"] != task.get("created_by"):
                    notification_data = NotificationCreate(
                        user_id=str(task["assignee_id"]),
                        type=NotificationType.TASK_STATUS_CHANGED,
                        title=f"任务状态更新：{task['title']}",
                        content=f"{current_user_name} 将任务「{task['title']}」的状态更新为「{status_name}」",
                        related_type=RelatedObjectType.TASK,
                        related_id=task_id
                    )
                    asyncio.create_task(
                        NotificationService.create_notification(db=self.db, notification_data=notification_data, send_email=False)
                    )
                
                # 如果状态变更为完成状态，发送完成通知
                validator = get_state_validator(self.db)
                try:
                    state_info = await validator.get_state_info("task", new_status)
                    if state_info:
                        state_name = state_info.get("name", "") if isinstance(state_info, dict) else getattr(state_info, "name", "")
                        state_name_lower = state_name.lower() if state_name else ""
                        is_completed = any(keyword in state_name_lower for keyword in ["完成", "已完成", "完成状态"])
                        if is_completed and task.get("assignee_id") and task["assignee_id"] != user_id:
                            notification_data = NotificationCreate(
                                user_id=str(task["assignee_id"]),
                                type=NotificationType.TASK_COMPLETED,
                                title=f"任务完成：{task['title']}",
                                content=f"任务「{task['title']}」已完成",
                                related_type=RelatedObjectType.TASK,
                                related_id=task_id
                            )
                            asyncio.create_task(
                                NotificationService.create_notification(db=self.db, notification_data=notification_data, send_email=True)
                            )
                except Exception as e:
                    logger.warning(f"判断任务完成状态失败: {str(e)}")
        except Exception as e:
            logger.warning(f"发送任务状态变更通知失败: {str(e)}")
        
        return task_data
    
    async def update_task_assignee(
        self,
        task_id: str,
        assignee_update: TaskAssigneeUpdate,
        current_user: dict
    ) -> Dict[str, Any]:
        """
        更新任务负责人
        """
        object_id = self._validate_object_id(task_id, "任务ID")
        
        # 检查任务是否存在
        task = await self.db.tasks.find_one({"_id": object_id})
        if not task:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_404_NOT_FOUND', 404),
                detail="Task not found"
            )
        
        # 权限检查
        user_permissions = current_user.get("permissions", [])
        user_id = ObjectId(current_user.get("user_id"))
        
        has_permission = (
            Permissions.TASK_ASSIGN in user_permissions or
            Permissions.ADMIN in user_permissions or
            task.get("created_by") == user_id
        )
        
        if not has_permission and task.get("project_id"):
            project = await self.db.projects.find_one({"_id": task["project_id"]})
            if project:
                has_permission = (
                    project["created_by"] == user_id or
                    any(
                        member["user_id"] == user_id and "task:assign" in member.get("permissions", [])
                        for member in project.get("members", [])
                    )
                )
        
        if not has_permission:
            raise HTTPException(
                status_code=self._get_status_code('HTTP_403_FORBIDDEN', 403),
                detail="Not enough permissions to assign task"
            )
        
        # 验证新负责人是否存在
        assignee_object_id = None
        if assignee_update.assignee_id:
            assignee_object_id = self._validate_object_id(assignee_update.assignee_id, "负责人ID")
            assignee = await self.db.users.find_one({"_id": assignee_object_id})
            if not assignee:
                raise HTTPException(
                    status_code=self._get_status_code('HTTP_404_NOT_FOUND', 404),
                    detail="Assignee not found"
                )
        
        # 获取旧负责人
        old_assignee_id = task.get("assignee_id")
        
        # 更新任务负责人
        await self.db.tasks.update_one(
            {"_id": object_id},
            {
                "$set": {
                    "assignee_id": assignee_object_id,
                    "updated_at": datetime.utcnow()
                }
            }
        )
        
        # 触发通知：如果负责人发生变化，通知新负责人
        if assignee_object_id and assignee_object_id != old_assignee_id:
            try:
                if assignee_object_id != user_id:
                    assignee = await self.db.users.find_one({"_id": assignee_object_id})
                    current_user_obj = await self.db.users.find_one({"_id": user_id})
                    current_user_name = current_user_obj.get("name") or current_user_obj.get("username", "系统") if current_user_obj else "系统"
                    
                    notification_data = NotificationCreate(
                        user_id=str(assignee_object_id),
                        type=NotificationType.TASK_ASSIGNED,
                        title=f"任务分配：{task['title']}",
                        content=f"{current_user_name} 将任务「{task['title']}」分配给了您",
                        related_type=RelatedObjectType.TASK,
                        related_id=task_id
                    )
                    asyncio.create_task(
                        NotificationService.create_notification(db=self.db, notification_data=notification_data, send_email=True)
                    )
                
                if old_assignee_id and old_assignee_id != user_id and old_assignee_id != assignee_object_id:
                    current_user_obj = await self.db.users.find_one({"_id": user_id})
                    current_user_name = current_user_obj.get("name") or current_user_obj.get("username", "系统") if current_user_obj else "系统"
                    new_assignee = await self.db.users.find_one({"_id": assignee_object_id})
                    new_assignee_name = new_assignee.get("name") or new_assignee.get("username", "其他用户") if new_assignee else "其他用户"
                    
                    notification_data = NotificationCreate(
                        user_id=str(old_assignee_id),
                        type=NotificationType.TASK_UPDATED,
                        title=f"任务重新分配：{task['title']}",
                        content=f"{current_user_name} 将任务「{task['title']}」重新分配给了 {new_assignee_name}",
                        related_type=RelatedObjectType.TASK,
                        related_id=task_id
                    )
                    asyncio.create_task(
                        NotificationService.create_notification(db=self.db, notification_data=notification_data, send_email=False)
                    )
            except Exception as e:
                logger.warning(f"发送任务分配通知失败: {str(e)}")
        
        return {"id": task_id}

